package Tracer;

import java.awt.Point;
import java.io.IOException;
import java.util.Date;
import java.util.Vector;

import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import XMLScene.RTCamera;

import XMLScene.RTImportXML;

public class RTShellScriptMain {

	/**
	 * This is the main function for generating movie
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		String filePath = args[1];
		String fileName = args[0].split("/")[1];
		String outputFolder = args[0].split("/")[0] + "/Output/";
		String[] a = fileName.split(".xml");
		String fileTitle = a[0];

		int threadNum = 1;

		RTCanvas canvas = new RTCanvas();

		// read the arguments
		Vector<String> argumentCount = new Vector<String>();
		for (int i = 2; i < args.length; i++) {
			if (args[i].equals("-z")) {
				canvas.setZoom(Integer.valueOf(args[i + 1]).intValue());
				argumentCount.addElement("z");
			} else if (args[i].equals("-x")) {
				canvas.setXpix(Integer.valueOf(args[i + 1]).intValue());
				argumentCount.addElement("x");
			} else if (args[i].equals("-y")) {
				canvas.setYpix(Integer.valueOf(args[i + 1]).intValue());
				argumentCount.addElement("y");
			} else if (args[i].equals("-w")) {
				canvas.setWidth(Integer.valueOf(args[i + 1]).intValue());
				argumentCount.addElement("w");
			} else if (args[i].equals("-h")) {
				canvas.setHeight(Integer.valueOf(args[i + 1]).intValue());
				argumentCount.addElement("h");
			} else if (args[i].equals("-q")) {
				canvas.setIsShadowingReflection(false);
				argumentCount.addElement("q");
			} else if (args[i].equals("-r") || args[i].equals("-d")) {
				canvas.setReflectionDepth(Integer.valueOf(args[i + 1])
						.intValue());
				argumentCount.addElement("r");
			} else if (args[i].equals("-t")) {
				canvas.setIsCalTraceTime(true);
				argumentCount.addElement("t");
			} else if (args[i].equals("-p")) {
				threadNum = Integer.valueOf(args[++i]).intValue();
				argumentCount.addElement("p");
			} else {
				throw new IllegalArgumentException("Argument are illegal!");
			}
			i++;
		}
		if (!argumentCount.contains("z")) {
			throw new IllegalArgumentException(
					"Pls input argument again, use -z to set zoom value!");
		} else if (!argumentCount.contains("x")) {
			throw new IllegalArgumentException(
					"Pls input argument again, use -x to set pixel x value!");
		} else if (!argumentCount.contains("y")) {
			throw new IllegalArgumentException(
					"Pls input argument again, use -y to set pixel y value!");
		} else if (!argumentCount.contains("w")) {
			throw new IllegalArgumentException(
					"Pls input argument again, use -w to set width value!");
		} else if (!argumentCount.contains("h")) {
			throw new IllegalArgumentException(
					"Pls input argument again, use -h to set height value!");
		}
		RTImportXML importXML = new RTImportXML();
		XMLReader parser;
		try {
			parser = XMLReaderFactory.createXMLReader();
			parser.setFeature("http://xml.org/sax/features/validation", true);
			parser.setContentHandler(importXML);
			try {
				parser.parse(filePath + args[0]);
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (SAXException e1) {
			e1.printStackTrace();
		}
		RTCamera camera = importXML.getCamera();

		// get the location of camera
		RTVector Ce = camera.getLocationVector();
		// get the normalized Lookup Vector
		RTVector c = RTVector.normaliseVectors(RTVector.sumVectors(camera
				.getLookatVector(), RTVector.reverseVector(Ce)));
		// right direction
		RTVector Cr = RTVector.normaliseVectors(RTVector.crossProductVectors(
				camera.getSkyVector(), c));
		// left direction
		RTVector Cd = RTVector.normaliseVectors(RTVector.crossProductVectors(
				Cr, c));
		// relative Width and Height
		RTVector relativeWH = RTVector.sumVectors(RTVector.multipleVectors(Cr,
				(canvas.getWidth() / 2)), RTVector.multipleVectors(Cd, (canvas
				.getHeight() / 2)));
		// calculate corner
		RTVector Cc = RTVector.sumVectors(RTVector.sumVectors(Ce, RTVector
				.multipleVectors(c, canvas.getZoom())), RTVector
				.reverseVector(relativeWH));

		canvas.setCornerUL(Cc);
		canvas.setRightD(Cr);
		canvas.setDownD(Cd);

		// add multi-threads
		
		RTBitmap resultBitmap = new RTBitmap((int) canvas.getXpix(),
				(int) canvas.getYpix());
		int xUnits = canvas.getXpix();
		int yUnits = canvas.getYpix();
		// Add the threads to parallelize

		// set thread limit to yUnits
		if (threadNum > yUnits) {
			threadNum = yUnits;
		}
		Point[][] splitedRayList = new Point[yUnits][xUnits];
		for (int i = 0; i < yUnits; i++) {
			for (int j = 0; j < xUnits; j++) {
				splitedRayList[i][j] = new Point();
				splitedRayList[i][j].setLocation(j, i);
			}
		}
		// The time count for total time consumed
		Date startTime = new Date();
		long l1 = startTime.getTime();
		ThreadPool threadPool = new ThreadPool(threadNum); // create thread
		// pool
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// sleep 500 ms, to make all tasks run
		// run the tasks
		for (int i = 0; i < yUnits; i++) { // create yUnits tasks
			threadPool.execute(new RTCoreTracing(splitedRayList[i], importXML,
					resultBitmap,canvas));
		}
		threadPool.waitFinish(); // wait until all tasks finish
		threadPool.closePool(); // close thread pool

		Date completeTime = new Date();
		long l2 = completeTime.getTime();
		long difference = l2 - l1;
		if (canvas.getIsCalTraceTime()) {
			System.out.println("Tracetime: " + difference + " ms");
		}
		// write the bitmap to ppm
		resultBitmap.writeBitmapToBinaryPPM(filePath + outputFolder + fileTitle
				+ ".ppm");
	}
}
